#ifndef __M_TCPSERVER_H__
#define __M_TCPSERVER_H__

#pragma once

#include "connection.hpp"
#include "eventLoop.hpp"
#include "acceptor.hpp"
#include "loopThread.hpp"
#include "loopThreadPool.hpp"
#include <signal.h>

class TcpServer
{
using ConnectionCallback = std::function<void(const ConnectionPtr&)>;

private:
    uint16_t _port;
    uint64_t _next_id;
    std::unordered_map<uint64_t, ConnectionPtr> _connections;
    EventLoop _baseloop;
    Acceptor _acceptor;
    LoopThreadPool _pool;
    int _sec;
    bool _enable_inactive_release;//是否开启非活跃连接定时释放功能
    ConnectionCallback _connected_cb;
    ConnectionCallback _closed_cb;
    ConnectionCallback _message_cb;//业务处理回调
    ConnectionCallback _events_cb;

private:
    void createConnection(int sockfd)
    {
        //acceptor回调是在主线程中调用的
        _next_id++;
        ConnectionPtr connection(new Connection(_pool.getNextLoop(), _next_id, sockfd));//将新接收的通信连接挂到RR轮转到的loop对象上
        _connections.insert(std::make_pair(_next_id, connection));//将当前的connection添加到hash中 防止connection离开当前作用域后直接释放
        connection->setConnectedCallback(_connected_cb);//connection指针在channel调用事件回调时手动传入 需要用到占位符
        connection->setClosedCallback(_closed_cb);
        connection->setMessageCallback(_message_cb);
        connection->setSrvClosedCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));
        //connection->setEventsCallback(std::bind(OnEvents, std::placeholders::_1));
        //设置非活跃连接超时关闭的定时任务 10s后没有收到客户端的消息便断开与客户端的连接
        //下面这两个函数内部会调用runInLoop 当前connection对象的loop与主线程id不匹配 主线程会将添加定时任务和设置读事件监控会被压入从线程loop的任务池 再唤醒evfd后处理s
        if (_enable_inactive_release)
            connection->enableInactiveRelease(_sec);//放到读事件监控之前 因为一旦开启监控 如果连接出现问题直接调用close回调 那么连接关闭后再设置非活跃连接超时释放就会出问题
        connection->establishConnection();//设置读事件监控 执行OnConnect回调
        //通信连接的读事件监控以及各种事件和任务处理都是在从线程中进行的
        //LOG(DEG, "create a new connection");
    }

    void removeConnection(const ConnectionPtr& connection)
    {
        uint64_t cid = connection->getConnectionId();
        auto it = _connections.find(cid);
        if (it != _connections.end())
        {
            _connections.erase(cid);
            LOG(DEG, "remove a connection from connections hash");
        }
    }

public:
    TcpServer(uint16_t port)
    : _port(port),
      _next_id(0),
      _acceptor(_port, &_baseloop),
      _pool(&_baseloop),
      _enable_inactive_release(false)
    {
        _acceptor.setAcceptorCallback(std::bind(&TcpServer::createConnection, this, std::placeholders::_1));
        _acceptor.listen();
    }

    void setThreadCount(int count) { _pool.setThreadCount(count); }

    void setConnectedCallback(const ConnectionCallback& connected_cb) { _connected_cb = connected_cb; }

    void setClosedCallback(const ConnectionCallback& closed_cb) { _closed_cb = closed_cb; }

    void setMessageCallback(const ConnectionCallback& message_cb) { _message_cb = message_cb; }

    void setEventsCallback(const ConnectionCallback& events_cb) { _events_cb = events_cb; }

    void enableInactiveRelease(int sec) { _sec = sec; _enable_inactive_release = true; }

    void runAfter(uint32_t timeout, const TimerTask::TaskFunc& task)//在主线程添加定时任务
    {
        _next_id++;
        _baseloop.addTimerTask(_next_id, timeout, task);//_timerwheel会调用runInLoop 不用再添加runAfterInLoop函数
    }

    void start()
    {
        _pool.create();//create需要在main函数调用了设置从线程数量的接口后再调用
        _baseloop.start();//主线程调用epoll_wait开始监控监听套接字
    }

};

class NetWork
{
public:
    NetWork()
    {
        LOG(DEG, "SIGPIPE INIT");
        signal(SIGPIPE, SIG_IGN);//与客户端的连接已经关闭 但服务器仍向客户端发送消息会触发SIGPIPE信号导致程序退出 对该信号进行忽略避免退出
    }
};

static NetWork nw;

#endif
